package com.YapaStream.impl;

/*
 * Copyright (C) 2009 The Sipdroid Open Source Project
 * 
 * This file is part of Sipdroid (http://www.sipdroid.org)
 * 
 * Sipdroid is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This source code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this source code; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

// BEGIN android-note
// address length was changed from long to int for performance reasons.
// END android-note

import java.io.FileDescriptor;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketImpl;
import java.net.UnknownHostException;
import java.nio.channels.Channel;
// BEGIN android-removed
// import java.nio.channels.SelectableChannel;
// END android-removed
/*
 * 
 * This Class is used for native code wrap, the implement class of
 * INetworkSystem.
 * 
 */

public final class OSNetworkSystem {

	// ----------------------------------------------------
	// Class Variables
	// ----------------------------------------------------

	private static final int ERRORCODE_SOCKET_TIMEOUT = -209;

	private static OSNetworkSystem ref = new OSNetworkSystem();

	private static final int INETADDR_REACHABLE = 0;

	private static boolean isNetworkInited = false;

	// ----------------------------------------------------
	// Class Constructor
	// ----------------------------------------------------

	// can not be instantiated.
	private OSNetworkSystem() {
		super();
	}

	/*
	 * @return a static ref of this class
	 */
	public static OSNetworkSystem getOSNetworkSystem() {
		return ref;
	}

	// Useing when cache set/get is OK
	// public static native void oneTimeInitializationDatagram(
	// boolean jcl_IPv6_support);
	//
	// public static native void oneTimeInitializationSocket(
	// boolean jcl_IPv6_support);

	// --------------------------------------------------
	// java codes that wrap native codes
	// --------------------------------------------------

	public void createSocket(FileDescriptor fd, boolean preferIPv4Stack)
			throws IOException {
		createSocketImpl(fd, preferIPv4Stack);
	}

	public void createDatagramSocket(FileDescriptor fd, boolean preferIPv4Stack)
			throws SocketException {
		createDatagramSocketImpl(fd, preferIPv4Stack);
	}

	public int read(FileDescriptor aFD, byte[] data, int offset, int count,
			int timeout) throws IOException {
		return readSocketImpl(aFD, data, offset, count, timeout);
	}

	public int readDirect(FileDescriptor aFD, int address, int offset,
			int count, int timeout) throws IOException {
		return readSocketDirectImpl(aFD, address, offset, count, timeout);
	}

	public int write(FileDescriptor aFD, byte[] data, int offset, int count)
			throws IOException {
		return writeSocketImpl(aFD, data, offset, count);
	}

	public int writeDirect(FileDescriptor aFD, int address, int offset,
			int count) throws IOException {
		return writeSocketDirectImpl(aFD, address, offset, count);
	}

	public void setNonBlocking(FileDescriptor aFD, boolean block)
			throws IOException {
		setNonBlockingImpl(aFD, block);
	}

	public void connectDatagram(FileDescriptor aFD, int port, int trafficClass,
			InetAddress inetAddress) throws SocketException {
		connectDatagramImpl2(aFD, port, trafficClass, inetAddress);
	}

	public int connect(FileDescriptor aFD, int trafficClass,
			InetAddress inetAddress, int port) throws IOException {
		return connectSocketImpl(aFD, trafficClass, inetAddress, port);
	}

	// BEGIN android-changed
	public int connectWithTimeout(FileDescriptor aFD, int timeout,
			int trafficClass, InetAddress inetAddress, int port, int step,
			byte[] context) throws IOException {
		return connectWithTimeoutSocketImpl(aFD, timeout, trafficClass,
				inetAddress, port, step, context);
	}

	// END android-changed

	public void connectStreamWithTimeoutSocket(FileDescriptor aFD, int aport,
			int timeout, int trafficClass, InetAddress inetAddress)
			throws IOException {
		connectStreamWithTimeoutSocketImpl(aFD, aport, timeout, trafficClass,
				inetAddress);
	}

	public void bind(FileDescriptor aFD, int port, InetAddress inetAddress)
			throws SocketException {
		socketBindImpl(aFD, port, inetAddress);
	}

	public boolean bind2(FileDescriptor aFD, int port, boolean bindToDevice,
			InetAddress inetAddress) throws SocketException {
		return socketBindImpl2(aFD, port, bindToDevice, inetAddress);
	}

	public void accept(FileDescriptor fdServer, SocketImpl newSocket,
			FileDescriptor fdnewSocket, int timeout) throws IOException {
		acceptSocketImpl(fdServer, newSocket, fdnewSocket, timeout);
	}

	public int sendDatagram(FileDescriptor fd, byte[] data, int offset,
			int length, int port, boolean bindToDevice, int trafficClass,
			InetAddress inetAddress) throws IOException {
		return sendDatagramImpl(fd, data, offset, length, port, bindToDevice,
				trafficClass, inetAddress);
	}

	public int sendDatagramDirect(FileDescriptor fd, int address, int offset,
			int length, int port, boolean bindToDevice, int trafficClass,
			InetAddress inetAddress) throws IOException {
		return sendDatagramDirectImpl(fd, address, offset, length, port,
				bindToDevice, trafficClass, inetAddress);
	}

	public int sendDatagram2(FileDescriptor fd, byte[] data, int offset,
			int length, int port, InetAddress inetAddress) throws IOException {
		return sendDatagramImpl2(fd, data, offset, length, port, inetAddress);
	}

	public int receiveDatagram(FileDescriptor aFD, DatagramPacket packet,
			byte[] data, int offset, int length, int receiveTimeout,
			boolean peek) throws IOException {
		return receiveDatagramImpl(aFD, packet, data, offset, length,
				receiveTimeout, peek);
	}

	public int receiveDatagramDirect(FileDescriptor aFD, DatagramPacket packet,
			int address, int offset, int length, int receiveTimeout,
			boolean peek) throws IOException {
		return receiveDatagramDirectImpl(aFD, packet, address, offset, length,
				receiveTimeout, peek);
	}

	public int recvConnectedDatagram(FileDescriptor aFD, DatagramPacket packet,
			byte[] data, int offset, int length, int receiveTimeout,
			boolean peek) throws IOException {
		return recvConnectedDatagramImpl(aFD, packet, data, offset, length,
				receiveTimeout, peek);
	}

	public int recvConnectedDatagramDirect(FileDescriptor aFD,
			DatagramPacket packet, int address, int offset, int length,
			int receiveTimeout, boolean peek) throws IOException {
		return recvConnectedDatagramDirectImpl(aFD, packet, address, offset,
				length, receiveTimeout, peek);
	}

	public int peekDatagram(FileDescriptor aFD, InetAddress sender,
			int receiveTimeout) throws IOException {
		return peekDatagramImpl(aFD, sender, receiveTimeout);
	}

	public int sendConnectedDatagram(FileDescriptor fd, byte[] data,
			int offset, int length, boolean bindToDevice) throws IOException {
		return sendConnectedDatagramImpl(fd, data, offset, length, bindToDevice);
	}

	public int sendConnectedDatagramDirect(FileDescriptor fd, int address,
			int offset, int length, boolean bindToDevice) throws IOException {
		return sendConnectedDatagramDirectImpl(fd, address, offset, length,
				bindToDevice);
	}

	public void disconnectDatagram(FileDescriptor aFD) throws SocketException {
		disconnectDatagramImpl(aFD);
	}

	public void createMulticastSocket(FileDescriptor aFD,
			boolean preferIPv4Stack) throws SocketException {
		createMulticastSocketImpl(aFD, preferIPv4Stack);
	}

	public void createServerStreamSocket(FileDescriptor aFD,
			boolean preferIPv4Stack) throws SocketException {
		createServerStreamSocketImpl(aFD, preferIPv4Stack);
	}

	public int receiveStream(FileDescriptor aFD, byte[] data, int offset,
			int count, int timeout) throws IOException {
		return receiveStreamImpl(aFD, data, offset, count, timeout);
	}

	public int sendStream(FileDescriptor fd, byte[] data, int offset, int count)
			throws IOException {
		return sendStreamImpl(fd, data, offset, count);
	}

	public void shutdownInput(FileDescriptor descriptor) throws IOException {
		shutdownInputImpl(descriptor);
	}

	public void shutdownOutput(FileDescriptor descriptor) throws IOException {
		shutdownOutputImpl(descriptor);
	}

	public boolean supportsUrgentData(FileDescriptor fd) {
		return supportsUrgentDataImpl(fd);
	}

	public void sendUrgentData(FileDescriptor fd, byte value) {
		sendUrgentDataImpl(fd, value);
	}

	public int availableStream(FileDescriptor aFD) throws SocketException {
		return availableStreamImpl(aFD);
	}

	// BEGIN android-removed
	// public void acceptStreamSocket(FileDescriptor fdServer,
	// SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
	// throws IOException {
	// acceptStreamSocketImpl(fdServer, newSocket, fdnewSocket, timeout);
	// }
	//
	// public void createStreamSocket(FileDescriptor aFD, boolean
	// preferIPv4Stack)
	// throws SocketException {
	// createStreamSocketImpl(aFD, preferIPv4Stack);
	// }
	// END android-removed

	public void listenStreamSocket(FileDescriptor aFD, int backlog)
			throws SocketException {
		listenStreamSocketImpl(aFD, backlog);
	}

	// BEGIN android-removed
	// public boolean isReachableByICMP(final InetAddress dest,
	// InetAddress source, final int ttl, final int timeout) {
	// return INETADDR_REACHABLE == isReachableByICMPImpl(dest, source, ttl,
	// timeout);
	// }
	// END android-removed

	/*
	 * 
	 * @param readChannels all channels interested in read and accept
	 * 
	 * @param writeChannels all channels interested in write and connect
	 * 
	 * @param timeout timeout in millis @return a set of channels that are ready
	 * for operation
	 * 
	 * @throws SocketException @return int array, each int approve one of the *
	 * channel if OK
	 */

	public int[] select(FileDescriptor[] readFDs, FileDescriptor[] writeFDs,
			long timeout) throws SocketException {
		int countRead = readFDs.length;
		int countWrite = writeFDs.length;
		int result = 0;
		if (0 == countRead + countWrite) {
			return (new int[0]);
		}
		int[] flags = new int[countRead + countWrite];

		// handle timeout in native
		result = selectImpl(readFDs, writeFDs, countRead, countWrite, flags,
				timeout);

		if (0 <= result) {
			return flags;
		}
		if (ERRORCODE_SOCKET_TIMEOUT == result) {
			return new int[0];
		}
		throw new SocketException();

	}

	public InetAddress getSocketLocalAddress(FileDescriptor aFD,
			boolean preferIPv6Addresses) {
		return getSocketLocalAddressImpl(aFD, preferIPv6Addresses);
	}

	/*
	 * Query the IP stack for the local port to which this socket is bound.
	 * 
	 * @param aFD the socket descriptor @param preferIPv6Addresses address
	 * preference for nodes that support both IPv4 and IPv6 @return int the
	 * local port to which the socket is bound
	 */
	public int getSocketLocalPort(FileDescriptor aFD,
			boolean preferIPv6Addresses) {
		return getSocketLocalPortImpl(aFD, preferIPv6Addresses);
	}

	/*
	 * Query the IP stack for the nominated socket option.
	 * 
	 * @param aFD the socket descriptor @param opt the socket option type
	 * 
	 * @return the nominated socket option value
	 * 
	 * @throws SocketException if the option is invalid
	 */
	public Object getSocketOption(FileDescriptor aFD, int opt)
			throws SocketException {
		return getSocketOptionImpl(aFD, opt);
	}

	/*
	 * Set the nominated socket option in the IP stack.
	 * 
	 * @param aFD the socket descriptor @param opt the option selector @param
	 * optVal the nominated option value
	 * 
	 * @throws SocketException if the option is invalid or cannot be set
	 */
	public void setSocketOption(FileDescriptor aFD, int opt, Object optVal)
			throws SocketException {
		setSocketOptionImpl(aFD, opt, optVal);
	}

	public int getSocketFlags() {
		return getSocketFlagsImpl();
	}

	/*
	 * Close the socket in the IP stack.
	 * 
	 * @param aFD the socket descriptor
	 */
	public void socketClose(FileDescriptor aFD) throws IOException {
		socketCloseImpl(aFD);
	}

	public InetAddress getHostByAddr(byte[] addr) throws UnknownHostException {
		return getHostByAddrImpl(addr);
	}

	public InetAddress getHostByName(String addr, boolean preferIPv6Addresses)
			throws UnknownHostException {
		return getHostByNameImpl(addr, preferIPv6Addresses);
	}

	public void setInetAddress(InetAddress sender, byte[] address) {
		setInetAddressImpl(sender, address);
	}

	// ---------------------------------------------------
	// Native Codes
	// ---------------------------------------------------

	static native void createSocketImpl(FileDescriptor fd,
			boolean preferIPv4Stack);

	/*
	 * Allocate a datagram socket in the IP stack. The socket is associated with
	 * the <code>aFD</code>.
	 * 
	 * @param aFD the FileDescriptor to associate with the socket @param
	 * preferIPv4Stack IP stack preference if underlying platform is V4/V6
	 * 
	 * @exception SocketException upon an allocation error
	 */
	static native void createDatagramSocketImpl(FileDescriptor aFD,
			boolean preferIPv4Stack) throws SocketException;

	static native int readSocketImpl(FileDescriptor aFD, byte[] data,
			int offset, int count, int timeout) throws IOException;

	static native int readSocketDirectImpl(FileDescriptor aFD, int address,
			int offset, int count, int timeout) throws IOException;

	static native int writeSocketImpl(FileDescriptor fd, byte[] data,
			int offset, int count) throws IOException;

	static native int writeSocketDirectImpl(FileDescriptor fd, int address,
			int offset, int count) throws IOException;

	static native void setNonBlockingImpl(FileDescriptor aFD, boolean block);

	static native int connectSocketImpl(FileDescriptor aFD, int trafficClass,
			InetAddress inetAddress, int port);

	// BEGIN android-changed
	static native int connectWithTimeoutSocketImpl(FileDescriptor aFD,
			int timeout, int trafficClass, InetAddress hostname, int port,
			int step, byte[] context);

	// END android-changed

	static native void connectStreamWithTimeoutSocketImpl(FileDescriptor aFD,
			int aport, int timeout, int trafficClass, InetAddress inetAddress)
			throws IOException;

	static native void socketBindImpl(FileDescriptor aFD, int port,
			InetAddress inetAddress) throws SocketException;

	static native void listenStreamSocketImpl(FileDescriptor aFD, int backlog)
			throws SocketException;

	static native int availableStreamImpl(FileDescriptor aFD)
			throws SocketException;

	static native void acceptSocketImpl(FileDescriptor fdServer,
			SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
			throws IOException;

	static native boolean supportsUrgentDataImpl(FileDescriptor fd);

	static native void sendUrgentDataImpl(FileDescriptor fd, byte value);

	/*
	 * Connect the socket to a port and address
	 * 
	 * @param aFD the FileDescriptor to associate with the socket @param port
	 * the port to connect to @param trafficClass the traffic Class to be used
	 * then the connection is made @param inetAddress address to connect to.
	 * 
	 * @exception SocketException if the connect fails
	 */
	static native void connectDatagramImpl2(FileDescriptor aFD, int port,
			int trafficClass, InetAddress inetAddress) throws SocketException;

	/*
	 * Disconnect the socket to a port and address
	 * 
	 * @param aFD the FileDescriptor to associate with the socket
	 * 
	 * @exception SocketException if the disconnect fails
	 */
	static native void disconnectDatagramImpl(FileDescriptor aFD)
			throws SocketException;

	/*
	 * Allocate a datagram socket in the IP stack. The socket is associated with
	 * the <code>aFD</code>.
	 * 
	 * @param aFD the FileDescriptor to associate with the socket @param
	 * preferIPv4Stack IP stack preference if underlying platform is V4/V6
	 * 
	 * @exception SocketException upon an allocation error
	 */

	/*
	 * Bind the socket to the port/localhost in the IP stack.
	 * 
	 * @param aFD the socket descriptor @param port the option selector @param
	 * bindToDevice bind the socket to the specified interface @param
	 * inetAddress address to connect to. @return if bind successful @exception
	 * SocketException thrown if bind operation fails
	 */
	static native boolean socketBindImpl2(FileDescriptor aFD, int port,
			boolean bindToDevice, InetAddress inetAddress)
			throws SocketException;

	/*
	 * Peek on the socket, update <code>sender</code> address and answer the
	 * sender port.
	 * 
	 * @param aFD the socket FileDescriptor @param sender an InetAddress, to be
	 * updated with the sender's address @param receiveTimeout the maximum
	 * length of time the socket should block, reading @return int the sender
	 * port
	 * 
	 * @exception IOException upon an read error or timeout
	 */
	static native int peekDatagramImpl(FileDescriptor aFD, InetAddress sender,
			int receiveTimeout) throws IOException;

	/*
	 * Recieve data on the socket into the specified buffer. The packet fields
	 * <code>data</code> & <code>length</code> are passed in addition to
	 * <code>packet</code> to eliminate the JNI field access calls.
	 * 
	 * @param aFD the socket FileDescriptor @param packet the DatagramPacket to
	 * receive into @param data the data buffer of the packet @param offset the
	 * offset in the data buffer @param length the length of the data buffer in
	 * the packet @param receiveTimeout the maximum length of time the socket
	 * should block, reading @param peek indicates to peek at the data @return
	 * number of data received @exception IOException upon an read error or
	 * timeout
	 */
	static native int receiveDatagramImpl(FileDescriptor aFD,
			DatagramPacket packet, byte[] data, int offset, int length,
			int receiveTimeout, boolean peek) throws IOException;

	static native int receiveDatagramDirectImpl(FileDescriptor aFD,
			DatagramPacket packet, int address, int offset, int length,
			int receiveTimeout, boolean peek) throws IOException;

	/*
	 * Recieve data on the connected socket into the specified buffer. The
	 * packet fields <code>data</code> & <code>length</code> are passed in
	 * addition to <code>packet</code> to eliminate the JNI field access calls.
	 * 
	 * @param aFD the socket FileDescriptor @param packet the DatagramPacket to
	 * receive into @param data the data buffer of the packet @param offset the
	 * offset in the data buffer @param length the length of the data buffer in
	 * the packet @param receiveTimeout the maximum length of time the socket
	 * should block, reading @param peek indicates to peek at the data @return
	 * number of data received @exception IOException upon an read error or
	 * timeout
	 */
	static native int recvConnectedDatagramImpl(FileDescriptor aFD,
			DatagramPacket packet, byte[] data, int offset, int length,
			int receiveTimeout, boolean peek) throws IOException;

	static native int recvConnectedDatagramDirectImpl(FileDescriptor aFD,
			DatagramPacket packet, int address, int offset, int length,
			int receiveTimeout, boolean peek) throws IOException;

	/*
	 * Send the <code>data</code> to the nominated target <code>address</code>
	 * and <code>port</code>. These values are derived from the DatagramPacket
	 * to reduce the field calls within JNI.
	 * 
	 * @param fd the socket FileDescriptor @param data the data buffer of the
	 * packet @param offset the offset in the data buffer @param length the
	 * length of the data buffer in the packet @param port the target host port
	 * 
	 * @param bindToDevice if bind to device @param trafficClass the traffic
	 * class to be used when the datagram is sent @param inetAddress address to
	 * connect to. @return number of data send
	 * 
	 * @exception IOException upon an read error or timeout
	 */
	static native int sendDatagramImpl(FileDescriptor fd, byte[] data,
			int offset, int length, int port, boolean bindToDevice,
			int trafficClass, InetAddress inetAddress) throws IOException;

	static native int sendDatagramDirectImpl(FileDescriptor fd, int address,
			int offset, int length, int port, boolean bindToDevice,
			int trafficClass, InetAddress inetAddress) throws IOException;

	/*
	 * Send the <code>data</code> to the address and port to which the was
	 * connnected and <code>port</code>.
	 * 
	 * @param fd the socket FileDescriptor @param data the data buffer of the
	 * packet @param offset the offset in the data buffer @param length the
	 * length of the data buffer in the packet @param bindToDevice not used,
	 * current kept in case needed as was the case for sendDatagramImpl @return
	 * number of data send @exception IOException upon an read error or timeout
	 */
	static native int sendConnectedDatagramImpl(FileDescriptor fd, byte[] data,
			int offset, int length, boolean bindToDevice) throws IOException;

	static native int sendConnectedDatagramDirectImpl(FileDescriptor fd,
			int address, int offset, int length, boolean bindToDevice)
			throws IOException;

	/*
	 * Answer the result of attempting to create a server stream socket in the
	 * IP stack. Any special options required for server sockets will be set by
	 * this method.
	 * 
	 * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4
	 * 
	 * @exception SocketException if an error occurs while creating the socket
	 */
	static native void createServerStreamSocketImpl(FileDescriptor aFD,
			boolean preferIPv4Stack) throws SocketException;

	/*
	 * Answer the result of attempting to create a multicast socket in the IP
	 * stack. Any special options required for server sockets will be set by
	 * this method.
	 * 
	 * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4
	 * 
	 * @exception SocketException if an error occurs while creating the socket
	 */
	static native void createMulticastSocketImpl(FileDescriptor aFD,
			boolean preferIPv4Stack) throws SocketException;

	/*
	 * Recieve at most <code>count</code> bytes into the buffer
	 * <code>data</code> at the <code>offset</code> on the socket.
	 * 
	 * @param aFD the socket FileDescriptor @param data the receive buffer
	 * 
	 * @param offset the offset into the buffer @param count the max number of
	 * bytes to receive @param timeout the max time the read operation should
	 * block waiting for data @return int the actual number of bytes read
	 * 
	 * @throws IOException @exception SocketException if an error occurs while
	 * reading
	 */
	static native int receiveStreamImpl(FileDescriptor aFD, byte[] data,
			int offset, int count, int timeout) throws IOException;

	/*
	 * Send <code>count</code> bytes from the buffer <code>data</code> at the
	 * <code>offset</code>, on the socket.
	 * 
	 * @param fd
	 * 
	 * @param data the send buffer @param offset the offset into the buffer
	 * 
	 * @param count the number of bytes to receive @return int the actual number
	 * of bytes sent @throws IOException @exception SocketException if an error
	 * occurs while writing
	 */
	static native int sendStreamImpl(FileDescriptor fd, byte[] data,
			int offset, int count) throws IOException;

	private native void shutdownInputImpl(FileDescriptor descriptor)
			throws IOException;

	private native void shutdownOutputImpl(FileDescriptor descriptor)
			throws IOException;

	// BEGIN android-removed
	// static native void acceptStreamSocketImpl(FileDescriptor fdServer,
	// SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
	// throws IOException;
	//
	// static native void createStreamSocketImpl(FileDescriptor aFD,
	// boolean preferIPv4Stack) throws SocketException;
	// END android-removed

	static native int sendDatagramImpl2(FileDescriptor fd, byte[] data,
			int offset, int length, int port, InetAddress inetAddress)
			throws IOException;

	static native int selectImpl(FileDescriptor[] readfd,
			FileDescriptor[] writefd, int cread, int cwirte, int[] flags,
			long timeout);

	static native InetAddress getSocketLocalAddressImpl(FileDescriptor aFD,
			boolean preferIPv6Addresses);

	/*
	 * Query the IP stack for the local port to which this socket is bound.
	 * 
	 * @param aFD the socket descriptor @param preferIPv6Addresses address
	 * preference for nodes that support both IPv4 and IPv6 @return int the
	 * local port to which the socket is bound
	 */
	static native int getSocketLocalPortImpl(FileDescriptor aFD,
			boolean preferIPv6Addresses);

	/*
	 * Query the IP stack for the nominated socket option.
	 * 
	 * @param aFD the socket descriptor @param opt the socket option type
	 * 
	 * @return the nominated socket option value
	 * 
	 * @throws SocketException if the option is invalid
	 */
	static native Object getSocketOptionImpl(FileDescriptor aFD, int opt)
			throws SocketException;

	/*
	 * Set the nominated socket option in the IP stack.
	 * 
	 * @param aFD the socket descriptor @param opt the option selector @param
	 * optVal the nominated option value
	 * 
	 * @throws SocketException if the option is invalid or cannot be set
	 */
	static native void setSocketOptionImpl(FileDescriptor aFD, int opt,
			Object optVal) throws SocketException;

	static native int getSocketFlagsImpl();

	/*
	 * Close the socket in the IP stack.
	 * 
	 * @param aFD the socket descriptor
	 */
	static native void socketCloseImpl(FileDescriptor aFD);

	static native InetAddress getHostByAddrImpl(byte[] addr)
			throws UnknownHostException;

	static native InetAddress getHostByNameImpl(String addr,
			boolean preferIPv6Addresses) throws UnknownHostException;

	native void setInetAddressImpl(InetAddress sender, byte[] address);

	// BEGIN android-removed
	// native int isReachableByICMPImpl(InetAddress addr, InetAddress local,
	// int ttl, int timeout);
	// END android-removed

	native Channel inheritedChannelImpl();

	public Channel inheritedChannel() {
		return inheritedChannelImpl();
	}

	public void oneTimeInitialization(boolean jcl_supports_ipv6) {
		if (!isNetworkInited) {
			oneTimeInitializationImpl(jcl_supports_ipv6);
			isNetworkInited = true;
		}
	}

	native void oneTimeInitializationImpl(boolean jcl_supports_ipv6);
}